const { randomFillSync } = require("node:crypto");

const urlAlphabet =
  "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";

/**
 * @description
 * Генерация рандомной строки с символами (`A-Za-z0-9_-`)
 *
 * @source https://github.com/ai/nanoid/blob/main/index.js
 *
 * @param {number} [size=21] Какого размера нужно генерировать строку. По умолчанию `21`
 * @returns {string}
 *
 * @example
 *
 * randomUID(100)
 * // iFA27Jf8Jtn7WpqN-S2mw1nrBt9j8cbtxkb1q672C5RZOGcI5UrlSJUmlswiuqYzZfC6TxVkonf0YwiOX-bMLTJXRTg0zokfhR_2
 *
 * randomUID()
 * // Qt8kPUze4vD3akfa4NNHX
 */
function randomUID(size = 21) {
  const pool = Buffer.allocUnsafe(size * 128);
  randomFillSync(pool);

  let uid = "";
  for (let i = 0; i < size; i++) uid += urlAlphabet[pool[i] & 63];

  return uid;
}

/**
 * @description
 * Генерация UUID v7
 *
 * @source https://stackoverflow.com/a/77391845
 *
 * @returns {string}
 *
 * @example
 *
 * UUIDv7()
 * // 018cdb97-0cd4-7000-90e0-709c93aaca9e
 */
function UUIDv7() {
  let prevTimestamp = -1;
  let seq = 0;

  const timestamp = Math.max(Date.now(), prevTimestamp);
  seq = timestamp === prevTimestamp ? seq + 1 : 0;
  prevTimestamp = timestamp;

  const uint32Array = new Uint32Array(2);
  randomFillSync(uint32Array);

  uint32Array[0] = (0b10 << (32 - 2)) | (uint32Array[0] >>> 2);

  const digits =
    timestamp.toString(16).padStart(48 / 4, "0") +
    "7" +
    seq.toString(16).padStart(12 / 4, "0") +
    uint32Array[0].toString(16).padStart((2 + 62) / 2 / 4, "0") +
    uint32Array[1].toString(16).padStart((2 + 62) / 2 / 4, "0");

  return `${digits.slice(0, 8)}-${digits.slice(8, 12)}-${digits.slice(
    12,
    16
  )}-${digits.slice(16, 20)}-${digits.slice(20)}`;
}

module.exports = { randomUID, UUIDv7 };
